module cache_tag_mng 
#(                                  
    // Set the size of cache
    parameter ADDR_CACHE_WIDTH = 16,    //default cache size is 64 Kbytes, 2**16 = 64K

    // Set the size of cache line. Number of byte in a line = 2**CACHE_LINE_WIDTH 
    parameter CACHE_LINE_WIDTH = 7,     //default cache line is consists of 128 bytes, 2**7=127

    // Set the size of way for a N-way set associative cache
    parameter WAY_WIDTH = 2,            
    parameter NUM_WAY   = 4,            // NUM_WAY = 2**WAY_WIDTH,

    // Set the size of main memory connected to l2 cache
    parameter ADDR_MEM_WIDTH = 28,      //default memory content 2**28 bytes = 256 Mbytes       

    // Set the size of SET, default SET size is 2**SET_WIDTH
    parameter SET_WIDTH = 10,           // SET_WIDTH=ADDR_MEM_WIDTH - ADDR_CACHE_WIDTH - WAY_WIDTH,

    // Set the width of TAG
    parameter TAG_WIDTH = 11           //ADDR_MEM_WIDTH - CACHE_LINE_WIDTH - SET_WIDTH
)

(
    input   clk,
    input   rst,
    input   [ADDR_MEM_WIDTH-1:0]    addr_mem,
    
    input   valid_arb2tag,
    output  ready_arb2tag,    
    input   ready_tag2rpbuf,
    output  valid_tag2rpbuf,
    input   ready_tag2rout,
    output  valid_tag2rout,
    input   ready_tag2ftch,
    output  valid_tag2ftch,

    input   wr_rd,           //write or read indicator - '0' read : '1' write
    input   repalce_done,
    input   write_policy   
);

wire   [NUM_WAY-1:0]   way_replace;

wire   [SET_WIDTH-1:0] set_rqst;
wire   [TAG_WIDTH-1:0] tag_rqst;
    wire   en_update;
    wire   empty_update;
    wire   valid_update;
    wire   dirty_update; 
    wire   lock_update;
    wire   [SET_WIDTH-1:0] set_update;
    wire   [TAG_WIDTH-1:0] tag_update;
    wire  empty;
    wire  valid; 
    wire  dirty; 
    wire  lock;  
    wire  cache_hit;   // hit flag of each way
    wire  [NUM_WAY-1:0]   way_hit;

tag_mem #(.NUM_WAY(NUM_WAY),.SET_WIDTH(SET_WIDTH),.TAG_WIDTH(TAG_WIDTH)) tag_mem
(
    .clk(clk),
    .rst(rst),
    .valid_arb2tag(valid_arb2tag),
    .ready_arb2tag(ready_arb2tag),
    .way_replace(way_replace),
    .set_rqst(set_rqst),
    .tag_rqst(tag_rqst),

    .en_update(en_update),
    .empty_update(empty_update),
    .valid_update(valid_update),
    .dirty_update(dirty_update), 
    .lock_update(lock_update),
    .set_update(set_update),
    .tag_update(tag_update),

    .empty_o(empty), 
    .valid_o(valid), 
    .dirty_o(dirty), 
    .lock_o(lock),  
    .cache_hit(cache_hit),   // hit flag of each way
    .way_hit(way_hit)
);


ctrl_unit #(.NUM_WAY(NUM_WAY),.SET_WIDTH(SET_WIDTH),.TAG_WIDTH(TAG_WIDTH)) ctrl_unit
(
    .clk(clk),
    .rst(rst),

    .valid_arb2tag(valid_arb2tag),
    .ready_arb2tag(ready_arb2tag),
    .ready_tag2rpbuf(ready_tag2rpbuf),
    .valid_tag2rpbuf(valid_tag2rpbuf),
    .ready_tag2rout(ready_tag2rout),
    .valid_tag2rout(valid_tag2rout),
    .ready_tag2ftch(ready_tag2ftch),
    .valid_tag2ftch(valid_tag2ftch),


    .repalce_done(repalce_done),
    .wr_rd(wr_rd),           //write or read indicator - '0' read : '1' write
    .write_policy(write_policy),    

    .way_evict(way_evict),
    .set_rqst(set_rqst),
    .tag_rqst(tag_rqst),

    .cache_hit(cache_hit),   // hit flag of each way    
    .empty_i(empty),
    .valid_i(valid),
   .dirty_i(dirty), 
    .lock_i(lock),

    .en_update(en_update),
    .empty_update(empty_update),
    .valid_update(valid_update),
    .dirty_update(dirty_update), 
   . lock_update(lock_update),
    .set_update(set_update),
    .tag_update(tag_update)
);

evict_mng #(.NUM_WAY(NUM_WAY),.SET_WIDTH(SET_WIDTH),.TAG_WIDTH(TAG_WIDTH)) evict_mng
(
    .clk(clk),
    .rst(rst),
    .valid_arb2tag(valid_arb2tag),
    .ready_arb2tag(ready_arb2tag),

    .evict_policy(evict_policy),
   .data_i(data_load),
    .data_o(data_update),   
    .en_wr(en_wr),

    .cache_hit(cache_hit),   // hit flag of each way
    .way_evict(way_evict),
    .way_hit(way_hit),
    .empty(empty),
    .valid(valid)
);


evict_mem #(.NUM_WAY(NUM_WAY),.SET_WIDTH(SET_WIDTH)) evict_mem 

(
    .clk(clk),
    .rst(rst),
    .valid_arb2tag(valid_arb2tag),
    .ready_arb2tag(ready_arb2tag),
    .set_mem(set_mem),   // Main memory address
    .data_i(data_update),    // Data written to memory
    .data_o(data_load)    // Data written to memory
);

endmodule
